﻿using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Web;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Runtime;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
using PD.ShP.Code;
using PD.ShP.Code.DataModel;

namespace PD.ShP.WorkflowActivities
{
    /// <summary>
    /// Creates a Windows SharePoint Services task for workflow, and handles its processing .
    /// </summary>
    [ActivityValidator(typeof(InvoiceProcessingTaskActivityValidator))]
    public partial class InvoiceProcessingTaskActivity : SequenceActivity
    {
        #region Fields

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.CorrelationToken property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty CorrelationTokenProperty = DependencyProperty.Register("CorrelationToken", typeof(CorrelationToken), typeof(InvoiceProcessingTaskActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.WorkflowToken property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty WorkflowTokenProperty = DependencyProperty.Register("WorkflowToken", typeof(CorrelationToken), typeof(InvoiceProcessingTaskActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.ParameterBindings property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(InvoiceProcessingTaskActivity), new PropertyMetadata(DependencyPropertyOptions.ReadOnly | DependencyPropertyOptions.Metadata, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.WorkflowContext property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty WorkflowContextProperty = DependencyProperty.Register("WorkflowContext", typeof(WorkflowContext), typeof(InvoiceProcessingTaskActivity));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.CreateTaskSpecialPermissions property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty CreateTaskSpecialPermissionsProperty = DependencyProperty.Register("CreateTaskSpecialPermissions", typeof(HybridDictionary), typeof(InvoiceProcessingTaskActivity));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.AssignedTo property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty AssignedToProperty = DependencyProperty.Register("AssignedTo", typeof(string), typeof(InvoiceProcessingTaskActivity));

        /// <summary>
        /// Represents the System.Workflow.ComponentModel.DependencyProperty that targets the PD.ShP.WorkflowActivities.InvoiceProcessingTaskActivity.Title property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "A dependency property must be static and start with uppercase.")]
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(InvoiceProcessingTaskActivity));

        /// <summary>
        /// The properties of the currently processing task.
        /// </summary>
        private TaskProperties workflowTaskProperties;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="InvoiceProcessingTaskActivity"/> class.
        /// </summary>
        public InvoiceProcessingTaskActivity()
        {
            this.InitializeComponent();
            this.SetReadOnlyPropertyValue(InvoiceProcessingTaskActivity.ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
            this.CreateTaskSpecialPermissions = new HybridDictionary();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InvoiceProcessingTaskActivity"/> class.
        /// </summary>
        /// <param name="name">The user-defined name of the activity.</param>
        public InvoiceProcessingTaskActivity(string name)
            : base(name)
        {
            this.InitializeComponent();
            this.SetReadOnlyPropertyValue(InvoiceProcessingTaskActivity.ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
            this.CreateTaskSpecialPermissions = new HybridDictionary();
        }

        #endregion Constructors

        #region Dependency Properties

        /// <summary>
        /// Gets or sets the System.Workflow.Runtime.CorrelationToken for the external methods.
        /// </summary>
        /// <value>
        /// The correlation token for the external methods.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        [DefaultValue(null)]
        [TypeConverter("System.Workflow.Activities.CorrelationTokenTypeConverter, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
        [MergableProperty(false)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [CategoryAttribute("Activity")]
        public CorrelationToken CorrelationToken
        {
            get
            {
                return (CorrelationToken)this.GetValue(InvoiceProcessingTaskActivity.CorrelationTokenProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.CorrelationTokenProperty, value);
                this.CreateUserTask.CorrelationToken = value;
                this.TaskChanged.CorrelationToken = value;
                this.TaskApproved.CorrelationToken = value;
                this.TaskRejected.CorrelationToken = value;
            }
        }

        /// <summary>
        /// Gets or sets the System.Workflow.Runtime.CorrelationToken for the external methods.
        /// </summary>
        /// <value>
        /// The correlation token for the external methods.
        /// </value>
        [RefreshProperties(RefreshProperties.All)]
        [DefaultValue(null)]
        [TypeConverter("System.Workflow.Activities.CorrelationTokenTypeConverter, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
        [MergableProperty(false)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        [CategoryAttribute("Activity")]
        public CorrelationToken WorkflowToken
        {
            get
            {
                return (CorrelationToken)this.GetValue(InvoiceProcessingTaskActivity.WorkflowTokenProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.WorkflowTokenProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the workflow context.
        /// </summary>
        /// <value>
        /// The workflow context.
        /// </value>
        [Browsable(true)]
        [CategoryAttribute("Misc")]
        public WorkflowContext WorkflowContext
        {
            get
            {
                return (WorkflowContext)this.GetValue(InvoiceProcessingTaskActivity.WorkflowContextProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.WorkflowContextProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the create task special permissions.
        /// </summary>
        /// <value>
        /// The create task special permissions.
        /// </value>
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [Browsable(false)]
        [CategoryAttribute("Misc")]
        public HybridDictionary CreateTaskSpecialPermissions
        {
            get
            {
                return (HybridDictionary)this.GetValue(InvoiceProcessingTaskActivity.CreateTaskSpecialPermissionsProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.CreateTaskSpecialPermissionsProperty, value);
            }
        }

        /// <summary>
        /// Gets the collection of bindable parameters as found in the external method's formal parameter list.
        /// </summary>
        /// <value>
        /// The System.Workflow.ComponentModel.WorkflowParameterBindingCollection of parameters to bind to.
        /// </value>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public WorkflowParameterBindingCollection ParameterBindings
        {
            get
            {
                return (WorkflowParameterBindingCollection)this.GetValue(InvoiceProcessingTaskActivity.ParameterBindingsProperty);
            }
        }

        /// <summary>
        /// Gets or sets the user name of the person to whom the workflow task is assigned.
        /// </summary>
        /// <value>
        /// The user name of the person to whom the workflow task is assigned.
        /// </value>
        [Browsable(true)]
        [CategoryAttribute("Context")]
        public string AssignedTo
        {
            get
            {
                return (string)this.GetValue(InvoiceProcessingTaskActivity.AssignedToProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.AssignedToProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the title of the workflow task.
        /// </summary>
        /// <value>
        /// The title of the workflow task.
        /// </value>
        [Browsable(true)]
        [CategoryAttribute("Context")]
        [DefaultValue(null)]
        public string Title
        {
            get
            {
                return (string)this.GetValue(InvoiceProcessingTaskActivity.TitleProperty);
            }

            set
            {
                this.SetValue(InvoiceProcessingTaskActivity.TitleProperty, value);
            }
        }

        #endregion Dependency Properties

        #region Properties

        /// <summary>
        /// Gets the workflow task id.
        /// </summary>
        [Browsable(false)]
        public Guid TaskId
        {
            get { return this.workflowTaskProperties.TaskId; }
        }

        /// <summary>
        /// Gets the approved status name.
        /// </summary>
        [Browsable(false)]
        public string ApprovedStatus
        {
            get { return WorkflowsResourceHelper.ReviewFeedback_ApprovedStatus; }
        }

        /// <summary>
        /// Gets the rejected status name.
        /// </summary>
        [Browsable(false)]
        public string RejectedStatus
        {
            get { return WorkflowsResourceHelper.ReviewFeedback_RejectedStatus; }
        }

        /// <summary>
        /// Gets the task approved history item title.
        /// </summary>
        [Browsable(false)]
        public virtual string TaskApprovedHistoryItemTitle
        {
            get
            {
                return string.IsNullOrEmpty(this.workflowTaskProperties.UserComment) ?
                       this.GetHistoryItemTitleWithEmptyComment(true) :
                       this.GetHistoryItemTitleWithComment(true);
            }
        }

        /// <summary>
        /// Gets the task rejected history item title.
        /// </summary>
        [Browsable(false)]
        public virtual string TaskRejectedHistoryItemTitle
        {
            get
            {
                return string.IsNullOrEmpty(this.workflowTaskProperties.UserComment) ?
                       this.GetHistoryItemTitleWithEmptyComment(false) :
                       this.GetHistoryItemTitleWithComment(false);
            }
        }

        /// <summary>
        /// Gets the invoice value.
        /// </summary>
        [Browsable(false)]
        public virtual double InvoiceValue
        {
            get
            {
                SPWeb web = this.WorkflowContext.Web;
                SPList invoicesList = web.Lists[new Guid(this.WorkflowContext.ListId)];
                SPListItem invoice = invoicesList.GetItemById(this.WorkflowContext.ItemId);
                return (invoice[Fields.TotalAmount] as double?).GetValueOrDefault();
            }
        }

        #endregion Properties

        #region Code Conditions

        /// <summary>
        /// Sets the result of task has been approved evaluation.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Workflow.Activities.ConditionalEventArgs"/> instance containing the event data.</param>
        private void TaskHasBeenApproved(object sender, ConditionalEventArgs e)
        {
            e.Result = this.workflowTaskProperties.IsApproved;
        }

        #endregion Code Conditions

        #region Handlers

        /// <summary>
        /// Handles the MethodInvoking event of the CreateTask control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CreateTask_MethodInvoking(object sender, EventArgs e)
        {
            CreateTask task = sender as CreateTask;
            this.workflowTaskProperties = new TaskProperties();
            task.TaskId = this.TaskId;
            task.TaskProperties = this.GetCommonTaskProperties();
        }

        /// <summary>
        /// Handles the Invoked event of the TaskChanged control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Workflow.Activities.ExternalDataEventArgs"/> instance containing the event data.</param>
        private void TaskChanged_Invoked(object sender, ExternalDataEventArgs e)
        {
            SPTaskServiceEventArgs args = (SPTaskServiceEventArgs)e;
            this.workflowTaskProperties.IsApproved = args.afterProperties.IsTaskApproved();
            this.workflowTaskProperties.IsTaskCompleted = true;
            this.workflowTaskProperties.UserComment = args.afterProperties.GetComment();
            this.workflowTaskProperties.Issuer = args.executor;
        }

        /// <summary>
        /// Handles the MethodInvoking event of the TaskApproved control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TaskApproved_MethodInvoking(object sender, EventArgs e)
        {
            this.CreateHistoryEvent(this.TaskApprovedHistoryItemTitle, SPWorkflowHistoryEventType.WorkflowComment);
        }

        /// <summary>
        /// Handles the MethodInvoking event of the TaskRejected control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TaskRejected_MethodInvoking(object sender, EventArgs e)
        {
            this.CreateHistoryEvent(this.TaskRejectedHistoryItemTitle, SPWorkflowHistoryEventType.WorkflowComment);
        }

        #endregion

        #region Helpers

        /// <summary>
        /// Gets the common task properties.
        /// </summary>
        /// <returns>
        /// The properties of a workflow task.
        /// </returns>
        private SPWorkflowTaskProperties GetCommonTaskProperties()
        {
            SPWorkflowTaskProperties taskProperties = new SPWorkflowTaskProperties();
            taskProperties.Title = this.Title;
            taskProperties.TaskType = 1;
            taskProperties.DueDate = DateTime.Now.AddDays(30);
            taskProperties.PercentComplete = (float)0;
            taskProperties.SetAllowDelegation(false);
            taskProperties.SetAllowChangeRequests(false);
            taskProperties.AssignedTo = string.IsNullOrEmpty(this.AssignedTo) ?
                HttpContext.Current.User.Identity.Name :
                this.AssignedTo;

            // set task permissions
            this.CreateTaskSpecialPermissions.Clear();
            this.CreateTaskSpecialPermissions.Add(taskProperties.AssignedTo, SPRoleType.Contributor);
            SPGroup ownerGroup = this.WorkflowContext.Web.AssociatedOwnerGroup;
            if (ownerGroup != null)
            {
                this.CreateTaskSpecialPermissions.Add(ownerGroup.LoginName, SPRoleType.Administrator);
            }

            return taskProperties;
        }

        /// <summary>
        /// Creates the history event.
        /// </summary>
        /// <param name="description">The description.</param>
        /// <param name="eventType">Type of the event.</param>
        private void CreateHistoryEvent(string description, SPWorkflowHistoryEventType eventType)
        {
            SPMember user = this.WorkflowContext.Web.SiteUsers.GetByLoginNameSafe(this.workflowTaskProperties.Issuer);
            SPWorkflow.CreateHistoryEvent(this.WorkflowContext.Web, this.WorkflowContext.WorkflowInstanceId, (int)eventType, user, TimeSpan.Zero, string.Empty, description, string.Empty);
        }

        /// <summary>
        /// Gets the history item title with comment.
        /// </summary>
        /// <param name="approved">if set to <c>true</c> the task has been approved.</param>
        /// <returns>
        /// The history item title with comment.
        /// </returns>
        private string GetHistoryItemTitleWithComment(bool approved)
        {
            string format = approved ?
                WorkflowsResourceHelper.GetTaskApproved_HistoryItem((uint)this.WorkflowContext.Web.Language) :
                WorkflowsResourceHelper.GetTaskRejected_HistoryItem((uint)this.WorkflowContext.Web.Language);
            return string.Format(
                CultureInfo.CurrentCulture,
                format,
                string.Format(CultureInfo.CurrentCulture, "{0:C2}", this.InvoiceValue),
                this.workflowTaskProperties.Issuer,
                this.workflowTaskProperties.UserComment);
        }

        /// <summary>
        /// Gets the history item title with empty comment.
        /// </summary>
        /// <param name="approved">if set to <c>true</c> the task has been approved.</param>
        /// <returns>
        /// The history item title with empty comment.
        /// </returns>
        private string GetHistoryItemTitleWithEmptyComment(bool approved)
        {
            string format = approved ?
                WorkflowsResourceHelper.GetTaskApproved_HistoryItem_EmptyComment((uint)this.WorkflowContext.Web.Language) :
                WorkflowsResourceHelper.GetTaskApproved_HistoryItem_EmptyComment((uint)this.WorkflowContext.Web.Language);
            return string.Format(
                CultureInfo.CurrentCulture,
                format,
                string.Format(CultureInfo.CurrentCulture, "{0:C2}", this.InvoiceValue),
                this.workflowTaskProperties.Issuer);
        }

        #endregion
    }
}
